package both.map.mapModel.unitTests;

import static org.junit.Assert.*;

import org.junit.Before;
import org.junit.Test;
import both.map.*;
import both.map.mapModel.*;
import java.awt.Dimension;
import java.util.HashMap;

import junit.framework.Assert;

public class ModelChunkTest {
	private ModelChunk testChunk;
	private ModelChunk updateChunk;
	private ModelChunk recipientChunk;
	private static final Dimension chunkSize = new Dimension(20,20);
	
	@Before
	public void setUp() throws Exception {
		testChunk = new ModelChunk(chunkSize);
		recipientChunk = new ModelChunk(chunkSize);
		VisibilityCell vc = (VisibilityCell) 
			testChunk.getLayer(LayerType.VISIBILITY).getCell(10, 10);
		vc.setVisibility(true,true);
	}

	@Test
	public void testModelChunkDimension() {
		try {
			new ModelChunk(chunkSize);
		} catch (Exception e) {
			fail("Exception thrown on new ModelChunk(Dimension) \n" + e);
		}
	}

	@Test
	public void testGetSize() {
		Assert.assertEquals(20, testChunk.getSize().height);
		ModelChunk a = new ModelChunk(new Dimension(3,3));
		Assert.assertEquals(3, a.getSize().width);
	}
	
	@Test
	public void testGetLayer() {
		ModelLayer vlayer = new ModelLayer(LayerType.VISIBILITY, chunkSize);
		HashMap<LayerType, ModelLayer> layers = new HashMap<LayerType, ModelLayer>();
		layers.put(vlayer.getType(), vlayer);
		ModelChunk c = new ModelChunk(layers, chunkSize);
		ModelLayer v = c.getLayer(LayerType.VISIBILITY);
		Assert.assertSame(v,vlayer);
		Assert.assertNull(c.getLayer(LayerType.TERRAIN));
	}

	@Test
	public void testGetAllLayers() {
		for (LayerType l : testChunk.getAllLayers().keySet()) {
			Assert.assertNotNull(testChunk.getLayer(l));
			Assert.assertSame(testChunk.getAllLayers().get(l), testChunk.getLayer(l));
		}
		
	}

	@Test
	public void testUpdate() {
		TerrainCell tc = (TerrainCell) recipientChunk.getLayer(LayerType.TERRAIN).getCell(10,10);
		Assert.assertEquals(TerrainType.empty, tc.getTerrainType());
		VisibilityCell vc = (VisibilityCell) recipientChunk.getLayer(LayerType.VISIBILITY).getCell(10,10);
		Assert.assertFalse(vc.hasBeenSeen());
		updateChunk = testChunk.grabUpdate();
		Assert.assertNotNull(updateChunk);
		try {
			recipientChunk.applyUpdate(updateChunk);
		} catch (UpdateStatusException e) {
			Assert.fail(e.toString() + " - exception thrown in updatechunk");
		}
		Assert.assertNull(testChunk.grabUpdate());
		Assert.assertNotNull(recipientChunk.grabUpdate());
		Assert.assertEquals(TerrainType.empty, tc.getTerrainType());
		Assert.assertTrue(vc.hasBeenSeen());
		TerrainCell testtcCell = (TerrainCell) testChunk.getLayer(LayerType.TERRAIN).getCell(10,10);
		testtcCell.reassignTerrain(TerrainType.water);
		updateChunk = testChunk.grabUpdate();
		Assert.assertNotNull(updateChunk);
		try {
			recipientChunk.applyUpdate(updateChunk);
		} catch (UpdateStatusException e) {
			Assert.fail(e.toString() + " - exception thrown in updatechunk");
		}
		Assert.assertEquals(TerrainType.water, tc.getTerrainType());		
	}
	
	@Test
	public void testUpdateBadInputs()
	{
		try {
			testChunk.applyUpdate(new ModelChunk(new Dimension(10,5)));
			fail("Should have thrown an exception for wrong dimension chunk");
		} catch (IllegalArgumentException e) {
		} catch (UpdateStatusException e) {
			fail("Thrown UpdateStatusException for an update that should have" +
					" thrown an IllegalArgumentException first"); 
		}
		
		HashMap<LayerType, ModelLayer> layers = new HashMap<LayerType, ModelLayer>();
		layers.put(LayerType.VISIBILITY, new ModelLayer(LayerType.VISIBILITY, chunkSize));
		ModelChunk oneLayeredChunk = new ModelChunk(layers, chunkSize);
		HashMap<LayerType, ModelLayer> multi = new HashMap<LayerType, ModelLayer>();
		multi.put(LayerType.TERRAIN, new ModelLayer(LayerType.TERRAIN, chunkSize));
		multi.put(LayerType.TOKEN, new ModelLayer(LayerType.TOKEN, chunkSize));
		ModelChunk multiLayeredChunk = new ModelChunk(multi, chunkSize);
		
		try {
			oneLayeredChunk.applyUpdate(multiLayeredChunk);
			fail("Should have UpdateStatusException by now, thrown due to mismatched layers in" +
					" update chunks and updated chunk");
		} catch (UpdateStatusException e) {
			// good!
		}
	}

}
